import { Command } from '../utils/cli-handler.js';
import { logger } from '../../core/logger.js';
import { composeColors, color } from '../../core/color.js';
import { compressDirectory } from '../utils/compress.js';
import { loadConfig } from '../../core/config.js';
import { KeyWatcher } from '../utils/key-watcher.js';
import { Spinner } from '../utils/spinner.js';
import { getRoboPackageJson, openBrowser, cleanTempDir, getPodStatusColor } from '../utils/utils.js';
import { RoboPlay } from '../../roboplay/client.js';
import { streamDeployment } from '../../roboplay/deploy.js';
import { RoboPlaySession } from '../../roboplay/session.js';
import { loginAction } from './login.js';
import { Mode } from '../../core/mode.js';
import { Env } from '../../core/env.js';
import path from 'node:path';

const Highlight = composeColors(color.bold, color.cyan);
const Indent = " ".repeat(3);
const Space = " ".repeat(8);
const command = new Command("deploy").description("Deploys your bot to RoboPlay!").option("-s", "--silent", "do not print anything").option("-v", "--verbose", "print more information for debugging").option("-h", "--help", "Shows the available command options").handler(deployAction);
var deploy_default = command;
async function deployAction(_args, options) {
  logger({
    enabled: !options.silent,
    level: options.verbose ? "debug" : "info"
  });
  if (!process.env.NODE_ENV) {
    process.env.NODE_ENV = "production";
  }
  const defaultMode = Mode.get();
  await Env.load({ mode: defaultMode });
  let session = await RoboPlaySession.get();
  let pod = session?.pods?.[0];
  if (!session || !pod) {
    await loginAction([], {
      silent: options.silent,
      verbose: options.verbose
    });
    session = await RoboPlaySession.get();
    pod = session?.pods?.[0];
  }
  if (!session || !pod) {
    logger.error(`You must be logged in to deploy to RoboPlay. Run ${Highlight("npx robo login")} to get started.`);
    return;
  }
  const config = await loadConfig("robo", true);
  if (config.experimental?.disableBot) {
    logger.warn("Sorry, only bots are supported right now!");
    return;
  }
  const spinner = new Spinner();
  const roboPackageJson = await getRoboPackageJson();
  const roboName = roboPackageJson?.name ?? "unknown";
  logger.log("\n" + Indent, `Thank you for using ${color.bold("RoboPlay")} \u2728`);
  logger.log("\n" + Indent, color.bold(`\u{1F512} Initiating deployment for ${Highlight(roboName)}`));
  spinner.setText(`${Indent} {{spinner}}  Requesting builder access...
`);
  spinner.start();
  const deployResult = await RoboPlay.Deploy.create({ bearerToken: session.userToken });
  const { deploy, error, upload, signature, success, url } = deployResult;
  spinner.stop(false);
  logger.debug(`Deployment result:`, deployResult);
  if (success) {
    logger.log("\r" + Indent, "   Builder access granted successfully");
  } else {
    logger.log("\r" + Indent, color.red("   " + error));
    logger.log("\n" + Indent, "\u2728 Join the Beta program in our Discord Server");
    logger.log(Indent + "   ", Highlight("https://robojs.dev/discord"), "\n");
    return;
  }
  const keyWatcher = new KeyWatcher(() => {
    spinner.getLogs().forEach(() => {
      process.stdout.write("\x1B[1A");
    });
    spinner.setLogs(`${Indent}    ${color.dim("Opening browser...")}`);
    openBrowser(url);
  });
  try {
    logger.log("\n" + Indent, color.bold("\u{1F4E6} Uploading bundle"));
    spinner.setText(`${Indent} {{spinner}}  Compressing project files...
`);
    spinner.start();
    const bundle = await createBundle();
    spinner.setText(`${Indent} {{spinner}}  4% uploaded...
`);
    logger.debug(`Uploading bundle...`);
    try {
      await RoboPlay.Deploy.upload({
        bundlePath: bundle,
        uploadKey: upload.key,
        uploadToken: upload.token,
        uploadUrl: upload.url
      });
    } catch (e) {
      await updateDeployment(deploy.id, session.userToken, "upload-failed");
      throw e;
    }
    spinner.stop(false);
    logger.log("\r" + Indent, "   Transmission complete", Space);
    logger.log("\n" + Indent, color.bold(`\u{1F680} Deploying to pod ${Highlight(pod.name)}`));
    const spinnerOptions = { podStatus: null, steps: {}, url };
    updateDeploymentSpinner(spinner, spinnerOptions);
    keyWatcher.start();
    spinner.start();
    streamDeployment({ deploymentId: deploy.id, signature }, (error2, data) => {
      if (error2) {
        keyWatcher.stop();
        spinner.stop(false);
        logger.log("\n");
        logger.error(error2);
        process.exit(1);
      }
      if (data.podStatus) {
        spinnerOptions.podStatus = data.podStatus;
      }
      if (data.deployment?.steps) {
        spinnerOptions.steps.init = data.deployment.steps.find((step) => step.name === "init")?.status;
        spinnerOptions.steps.build = data.deployment.steps.find((step) => step.name === "build")?.status;
        spinnerOptions.steps.deploy = data.deployment.steps.find((step) => step.name === "deploy")?.status;
      }
      updateDeploymentSpinner(spinner, spinnerOptions);
      if (["Completed", "Failed"].includes(data.deployment?.status)) {
        keyWatcher.stop();
        spinner.stop(false);
        updateDeploymentSpinner(null, spinnerOptions);
        const emoji = data.deployment?.status === "Completed" ? "\u{1F389}" : "\u274C";
        logger.log(Indent, emoji, color.bold(`Deployment ${data.deployment?.status.toLowerCase()}!${Space}${Space}
`));
        process.exit(data.deployment?.status === "Completed" ? 0 : 1);
      }
    });
    await Promise.all([
      loadPodStatus(pod.id, session.userToken, spinner, spinnerOptions),
      updateDeployment(deploy.id, session.userToken, "upload-success")
    ]);
  } catch (e) {
    keyWatcher.stop();
    spinner.stop(false);
    logger.log("\n");
    logger.error(e);
  } finally {
    logger.debug(`Cleaning up temporary files...`);
    await cleanTempDir();
  }
}
async function createBundle() {
  logger.debug(`Creating bundle...`);
  try {
    const currentTime = (/* @__PURE__ */ new Date()).toISOString().split(".")[0].replace(/[:-]/g, "");
    const projectName = path.basename(process.cwd()).toLowerCase();
    const fileName = `${projectName}-${currentTime}.robopack`;
    const outputPath = path.join(process.cwd(), ".robo", "temp", fileName);
    await compressDirectory(process.cwd(), outputPath, [
      ".git",
      "node_modules",
      `.robo${path.sep}build`,
      `.robo${path.sep}temp`
    ]);
    logger.debug(`Created bundle:`, outputPath);
    return outputPath;
  } catch (error) {
    logger.error("Error bundling directory:", error);
  }
}
async function loadPodStatus(podId, bearerToken, spinner, spinnerOptions) {
  const podStatus = await RoboPlay.Pod.status({ bearerToken, podId });
  if (podStatus.success) {
    spinnerOptions.podStatus = podStatus.status;
  } else {
    spinnerOptions.podStatus = podStatus.error;
  }
  updateDeploymentSpinner(spinner, spinnerOptions);
}
async function updateDeployment(deployId, bearerToken, event) {
  const result = await RoboPlay.Deploy.update({ bearerToken, deployId, event });
  if (!result.success) {
    throw new Error(result.error);
  }
}
function updateDeploymentSpinner(spinner, options) {
  const { podStatus, steps, url } = options;
  const queryIndex = url.indexOf("?");
  const cleanUrl = url?.substring(0, queryIndex !== -1 ? queryIndex : url.length);
  const podSpinner = podStatus ? "" : "{{spinner}} ";
  const podStatusColor = podStatus ? getPodStatusColor(podStatus) : color.yellow;
  const text = `${Indent}    Pod status: ${podSpinner}${composeColors(
    color.bold,
    podStatusColor
  )(podStatus ?? "Checking...")}${Space}

${Indent}    ${color.bold("Deployment Progress:")}
${Indent}    - Preparing: ${getStepStatus(steps.init)}${Space}
${Indent}    - Building: ${getStepStatus(steps.build)}${Space}
${Indent}    - Deploying: ${getStepStatus(steps.deploy)}${Space}

${Indent}    ${color.bold("Track live status:")}
${Indent}    ${color.blue(cleanUrl)}` + (spinner ? `

${Indent}    ${Highlight("Press Enter")} to open status page.
` : "\n");
  if (spinner) {
    spinner.setText(text, false);
  } else {
    logger.log("\r" + text);
  }
}
function getStepStatus(status) {
  switch (status) {
    case "Completed":
      return composeColors(color.bold, color.green)("\u2714 Done");
    case "Failed":
      return composeColors(color.bold, color.red)("\u2716 Failed");
    case "Running":
      return "{{spinner}} " + composeColors(color.bold, color.yellow)("In Progress");
    default:
      return composeColors(color.bold, color.dim)("Pending");
  }
}

export { deploy_default as default };
